package com.qianda.qdminiapp.controller.payment;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qianda.qdminiapp.common.constant.CommonConstant;
import com.qianda.qdminiapp.common.rabbitmq.MsgProducer;
import com.qianda.qdminiapp.common.util.PayUtil;
import com.qianda.qdminiapp.config.WxpayProperties;
import com.qianda.qdminiapp.dao.account.QqdAccountDao;
import com.qianda.qdminiapp.dao.account.QqdAccountTradeDao;
import com.qianda.qdminiapp.dao.order.QqdOrderInfoDao;
import com.qianda.qdminiapp.dao.order.QqdOrderRechargeDao;
import com.qianda.qdminiapp.dao.order.QqdOrderTowelDao;
import com.qianda.qdminiapp.dao.user.QqdUserDao;
import com.qianda.qdminiapp.domain.model.account.QqdAccount;
import com.qianda.qdminiapp.domain.model.account.QqdAccountTrade;
import com.qianda.qdminiapp.domain.model.order.QqdOrderInfo;
import com.qianda.qdminiapp.domain.model.order.QqdOrderRecharge;
import com.qianda.qdminiapp.domain.model.order.QqdOrderTowel;
import com.qianda.qdminiapp.domain.model.user.QqdUser;
import com.qianda.qdminiapp.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 微信支付异步通知
 * @ClassName WxPayNotify
 * @Author cw
 * @Date 2019/9/12 11:50
 * @Version 1.0
 */
@RestController
@RequestMapping("/wxpay")
public class WxPayNotify {
    private static Logger LOGGER = LoggerFactory.getLogger(WxPayNotify.class);

    @Autowired
    private WxpayProperties wxPayConfig;

    @Autowired
    private QqdOrderTowelDao qqdOrderTowelDao;

    @Autowired
    private MsgProducer msgProducer;

    @Autowired
    private QqdOrderTowelService qqdOrderTowelService;

    @Autowired
    private QqdOrderInfoDao qqdOrderInfoDao;

    @Autowired
    private QqdOrderRechargeDao qqdOrderRechargeDao;

    @Autowired
    private QqdAccountDao qqdAccountDao;

    @Autowired
    private QqdAccountTradeDao qqdAccountTradeDao;

    @Autowired
    private QqdAccountService qqdAccountService;
    @Autowired
    private QqdAccountTradeService qqdAccountTradeService;

    @Autowired
    private QqdUserDao userDao;

    @PostMapping("/wxPayNotify")
    public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
        LOGGER.info("-------------------------微信支付回调- start wxNotify-------------------------------");
        String line = null;
        StringBuilder sb = null;
        Map map = null;
        String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        try {
            BufferedReader br = new BufferedReader(
                    new InputStreamReader((ServletInputStream) request.getInputStream()));
            sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            // sb为微信返回的xml
            String notityXml = sb.toString();
            System.out.println(notityXml);
            LOGGER.info("微信支付通知返回xml:"+notityXml);

            map = PayUtil.doXMLParse(notityXml);
            String returnCode = (String) map.get("return_code");
            if ("SUCCESS".equals(returnCode)) {
                String sign = (String) map.get("sign");
                map.remove("sign");
                // 验证签名是否正确
                if (PayUtil.verify(PayUtil.createLinkString(map), sign, wxPayConfig.getKey(), "utf-8")) {
                   String orderNo= (String)map.get("out_trade_no");
                    LOGGER.info("{" + orderNo + "}订单支付成功，签名验证成功");

                    //判断订单类型
                    QueryWrapper<QqdOrderInfo> qqdOrderInfoQueryWrapper = new QueryWrapper<>();
                    qqdOrderInfoQueryWrapper.eq("order_no",orderNo).eq("status",CommonConstant.Status.STATUS_NORMAL);
                    QqdOrderInfo qqdOrderInfo = qqdOrderInfoDao.selectOne(qqdOrderInfoQueryWrapper);

                    QqdUser user = userDao.selectById(qqdOrderInfo.getOrderUserId());
                    qqdAccountTradeService.insert(qqdOrderInfo,user.getId());

                    //后续业务处理
                    if(qqdOrderInfo.getOrderType() == CommonConstant.QqdOrderType.QQD_ORDER_TYPE_BUY_TOWEL){
                        orderTowelHandler(qqdOrderInfo);
                    }else if(qqdOrderInfo.getOrderType() == CommonConstant.QqdOrderType.QQD_ORDER_TYPE_CHARGE){
                        rechargeOrder(qqdOrderInfo);
                    }

                } else {
                    LOGGER.info("微信支支付签名失败");
                }
            } else {
                LOGGER.info("微信返回支付未成功");
            }
        } catch (Exception e) {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            LOGGER.error("微信返回支付成功通知发生异常", e);
        }
        try {
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        } catch (Exception ex) {
            LOGGER.error("微信返回支付成功通知发生异常-流出现异常", ex);
        }

    }


    /**
     * 微信退款通知
     * @param request
     * @param response
     */
    @PostMapping("/wxRefundNotify")
    public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) {
        LOGGER.info("-------------------------微信退款成功通知回调- start wxNotify-------------------------------");
        String line = null;
        StringBuilder sb = null;
        Map map = null;
        String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        try {
            BufferedReader br = new BufferedReader(
                    new InputStreamReader((ServletInputStream) request.getInputStream()));
            sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            // sb为微信返回的xml
            String notityXml = sb.toString();
            System.out.println(notityXml);
            LOGGER.info("微信退款通知返回xml:"+notityXml);

            map = PayUtil.doXMLParse(notityXml);
            String returnCode = (String) map.get("return_code");
            if ("SUCCESS".equals(returnCode)) {
                String sign = (String) map.get("sign");
                map.remove("sign");
                // 验证签名是否正确
                if (PayUtil.verify(PayUtil.createLinkString(map), sign, wxPayConfig.getKey(), "utf-8")) {
                    String orderNo= (String)map.get("out_trade_no");
                    LOGGER.info("{" + orderNo + "}订单退款成功，签名验证成功");

                    QueryWrapper<QqdOrderTowel> qqdOrderTowelQueryWrapper = new QueryWrapper<>();
                    qqdOrderTowelQueryWrapper.eq("order_no",orderNo).eq("status", CommonConstant.Status.STATUS_NORMAL);
                    QqdOrderTowel qqdOrderTowel = qqdOrderTowelDao.selectOne(qqdOrderTowelQueryWrapper);
                    qqdOrderTowel.setOrderPayStatus(CommonConstant.PayStatus.PAY_STATUS_REFUND);
                    qqdOrderTowelService.updateById(qqdOrderTowel);


                } else {
                    LOGGER.info("微信退款签名失败");
                }
            } else {
                LOGGER.info("微信返回退款未成功");
            }
        } catch (Exception e) {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            LOGGER.error("微信返回退款成功通知发生异常", e);
        }
        try {
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
        } catch (Exception ex) {
            LOGGER.error("微信返回退款成功通知发生异常-流出现异常", ex);
        }

    }

    /*
     *  购巾订单处理
     * @Description
     * @Author cw
     * @Date 15:29 2019/9/17
     * @Param [qqdOrderInfo]
     * @return void
     **/
    private void orderTowelHandler(QqdOrderInfo qqdOrderInfo){
        QueryWrapper<QqdOrderTowel> qqdOrderTowelQueryWrapper = new QueryWrapper<>();
        qqdOrderTowelQueryWrapper.eq("order_no",qqdOrderInfo.getOrderNo()).eq("status", CommonConstant.Status.STATUS_NORMAL);
        QqdOrderTowel qqdOrderTowel = qqdOrderTowelDao.selectOne(qqdOrderTowelQueryWrapper);

        if(qqdOrderTowel.getOrderPayStatus() == CommonConstant.PayStatus.PAY_STATUS_WAIT){
            qqdOrderTowel.setOrderPayStatus(CommonConstant.PayStatus.PAY_STATUS_PAYED);
            qqdOrderTowel.setOrderStatus(CommonConstant.OrderOutTowelStatus.ORDER_OUT_TOWEL_STATUS_WORKING);
            qqdOrderTowelService.updateById(qqdOrderTowel);
            msgProducer.sendCommand(qqdOrderTowel, 3);
            Long orderId = qqdOrderTowel.getId();
            //18秒后判断订单是否还是出巾中，如果是就把订单改为出巾异常，且异常类型为出巾超时
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    QqdOrderTowel qqdOrderTowelnew = qqdOrderTowelService.getById(orderId);
                    if(qqdOrderTowelnew.getOrderStatus() == CommonConstant.OrderOutTowelStatus.ORDER_OUT_TOWEL_STATUS_WORKING){
                        qqdOrderTowelnew.setOrderStatus( CommonConstant.OrderOutTowelStatus.ORDER_OUT_TOWEL_STATUS_ERROR);//出巾异常
                        qqdOrderTowelnew.setOrderErrorType(CommonConstant.OrderErrorType.ORDER_ERROR_TYPE_13);// 异常原因: 出巾超时
                        qqdOrderTowelService.updateById(qqdOrderTowelnew);

                        OrderAndPaymentStrategy orderAndPaymentStrategy = PaymentSelector.getPaymentSelector(CommonConstant.PayType.PAY_TYPE_WX);

                        //发起退款
                        orderAndPaymentStrategy.refundPay(qqdOrderTowelnew);
                    }
                }
            },18000);

        }
    }

    /*
     * 充值订单充值成功后续处理
     * @Description
     * @Author cw
     * @Date 15:30 2019/9/17
     * @Param [qqdOrderInfo]
     * @return void
     **/
    private void rechargeOrder(QqdOrderInfo qqdOrderInfo){
        qqdAccountService.rechargeOrder(qqdOrderInfo);
    }


}
